/**
 * 泛型
 * 定义函数/类时 遇到类型不明确时 就可以使用泛型 实在是不知道返回值的类型是什么
 * 
 * T 代表任意类型(名字可以随便取) 保证类型不会被any关闭 也会进行类型的检查
 * 
 * 调用函数时 ts可以自动推断出类型
 * 
 * 可以多个定义泛型
 * 
 * 可以通过 interface + extends 关键字的方式约束泛型的类型 同时也会约束函数在调用时传入值的类型
 */


function fn<T>(a: T): T{
  return a;
}

// 调用函数 不指定泛型
fn(123)
// 调用函数 指定泛型
fn<string>("hello")

// 这里可以返回T | U 也可以返回T
function fn2<T, U>(a: T, b: U): T | U {
  return a; 
}

interface inter{
  length: number;
}
function fn3<T extends inter>(a: T): T{
  return a;
}

fn3([1, 2, 3])
fn3({ length: 10 })